/**
 * @format
 * @Author: TC
 * @Date: 2023-08-18 22:40:29
 * @Last Modified by: TC
 * @Last Modified time: 2025-05-25 20:45:21
 */

import { app } from "../../App";
import { IV2 } from "../../Interface/BaseInterface";
import { PolygonUnit } from "./PolygonUint";

export class AStarPathFinding {
    /**最大寻路次数 */
    private _maxStep: number = 500;
    private _openList: PolygonUnit[] = [];
    private _closeList: PolygonUnit[] = [];
    private _endPos: IV2 = null;
    private _triangleTempList: PolygonUnit[] = [];

    /**
     * 获取坐标所在多边形
     * @param x
     * @param y
     * @returns
     */
    private getPolygonByCoord(x: number, y: number): PolygonUnit {
        for (let polygon of app.navMeshMgr.polygonList) {
            if (polygon.pointInPolygon(x, y)) {
                return polygon;
            }
        }
        return null;
    }

    /**
     * 获取A星寻路网格索引
     * @param posStart
     * @param posEnd
     * @returns
     */
    getMeshIndexs(posStart: IV2, posEnd: IV2): number[] {
        let indexs: number[] = [];
        let polygonStart = this.getPolygonByCoord(posStart.x, posStart.y);
        let polygonEnd = this.getPolygonByCoord(posEnd.x, posEnd.y);
        if (!polygonStart || !polygonEnd) {
            return indexs;
        }
        this.clearParent();
        this._endPos = posEnd;
        let step: number = 0;

        this._openList = [];
        this._closeList = [];
        let curr = polygonStart;
        this._openList.push(curr);
        let p: PolygonUnit = null;
        while (1) {
            step++;
            if (step > this._maxStep) {
                p = null;
                break;
            }
            p = this.getMinFromOpen();
            app.mExtend.removeFromArr(p, this._openList);
            this._closeList.push(p);
            if (!p) {
                app.log.error("find min err");
                return [];
            }
            this.pushAroundIntoOpen(p);
            if (p == polygonEnd) {
                //到达终点
                // tApp.mConsole.log("get end");
                break;
            }
        }

        if (p) {
            while (p.parent) {
                indexs.unshift(p.polygon.index);
                p = p.parent;
            }
            //加入起点
            indexs.unshift(polygonStart.polygon.index);
        }

        return indexs;
    }

    /**
     * 从开放列表中获取最优多边形
     * @returns
     */
    private getMinFromOpen(): PolygonUnit {
        if (!this._openList) return null;
        let len: number = this._openList.length;
        if (0 == len) return null;
        let index: number = 0;
        for (let i = 1; i < len; i += 1) {
            if (this._openList[i].f < this._openList[index].f && this._openList[i].walkable) {
                index = i;
            }
        }
        return this._openList[index];
    }

    /**
     * 把周围的格子放到openlist
     * @param p
     */
    private pushAroundIntoOpen(p: PolygonUnit): void {
        let heighbours: PolygonUnit[] = p.neighbourArr;
        for (let i = 0, len = heighbours.length; i < len; i++) {
            let polygonTemp: PolygonUnit = heighbours[i];
            if (this.inCloseList(polygonTemp))
                //已在closelist中
                continue;
            if (!polygonTemp.walkable)
                //网格不可走
                continue;
            if (this.inOpenList(polygonTemp)) {
                //已在openlist中，重新计算fgh
                if (this.getF(polygonTemp, p) < polygonTemp.f) {
                    polygonTemp.calFGH(p, this._endPos);
                    polygonTemp.parent = p;
                    if (this._triangleTempList.indexOf(polygonTemp) < 0) this._triangleTempList.push(polygonTemp);
                }
            } else {
                let push: boolean = true;
                if (push) {
                    polygonTemp.parent = p;
                    this._openList.push(polygonTemp);
                    if (this._triangleTempList.indexOf(polygonTemp) < 0) this._triangleTempList.push(polygonTemp);
                }
            }
        }
    }

    private getF(p: PolygonUnit, parent: PolygonUnit): number {
        let math = app.mMath;
        let g = Math.abs(math.distance(p.getCenter(), parent.getCenter()));
        let h = Math.abs(math.distance(p.getCenter(), this._endPos));
        return g + h;
    }

    /**
     * 多边形是否在开放列表中
     * @param p
     * @returns
     */
    private inOpenList(p: PolygonUnit): boolean {
        return this._openList.indexOf(p) > -1;
    }

    /**
     * 多边形是否在封闭列表中
     * @param p
     * @returns
     */
    private inCloseList(p: PolygonUnit): boolean {
        return this._closeList.indexOf(p) > -1;
    }

    /**
     * 清除所有多边形的父节点
     */
    private clearParent(): void {
        this._triangleTempList.forEach((item) => {
            item.parent = null;
        });
        this._triangleTempList = [];
    }
}
